home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / COMMS / C101.ZIP / UUPC11XT.ZIP / RN / NG.C < prev    next >
C/C++ Source or Header  |  1992-11-22  |  34KB  |  1,353 lines

  1. /* $Header: E:\SRC\UUPC\RN\RCS\NG.C 1.2 1992/11/22 21:09:09 ahd Exp $
  2.  *
  3.  * $Log: NG.C $
  4.  * Revision 1.2  1992/11/22  21:09:09  ahd
  5.  * Back off use of strpool for memory allocation
  6.  *
  7.  * Revision 1.1  1992/11/21  06:14:58  ahd
  8.  * Initial
  9.  *
  10.  *
  11.  *    Rev 1.0   18 Nov 1990  0:21:50
  12.  * Initial revision.
  13.  * Revision 4.3.2.7  90/04/21  14:44:23  sob
  14.  * Revised previous patch insure that it does not decrement below zero.
  15.  *
  16.  * Revision 4.3.2.6  90/03/22  23:04:49  sob
  17.  * Fixes provided by Wayne Davison <drivax!davison>
  18.  *
  19.  * Revision 4.3.2.5  89/12/09  01:18:42  sob
  20.  * Fixed a bad call to nntpopen().
  21.  *
  22.  * Revision 4.3.2.4  89/11/28  01:51:20  sob
  23.  * Removed redundant #include directive.
  24.  *
  25.  * Revision 4.3.2.3  89/11/27  01:31:03  sob
  26.  * Altered NNTP code per ideas suggested by Bela Lubkin
  27.  * <filbo@gorn.santa-cruz.ca.us>
  28.  *
  29.  * Revision 4.3.2.2  89/11/26  22:53:35  sob
  30.  * Add new patches to make RRN be faster.
  31.  *
  32.  * Revision 4.3.2.1  89/11/06  00:54:27  sob
  33.  * Added RRN support from NNTP 1.5
  34.  *
  35.  * Revision 4.3.1.6  85/09/10  11:03:42  lwall
  36.  * Improved %m in in_char().
  37.  *
  38.  * Revision 4.3.1.5  85/09/05  12:34:37  lwall
  39.  * Catchup command could make unread article count too big.
  40.  *
  41.  * Revision 4.3.1.4  85/07/23  18:19:46  lwall
  42.  * Added MAILCALL environment variable.
  43.  *
  44.  * Revision 4.3.1.3  85/05/16  16:48:09  lwall
  45.  * Fixed unsubsubscribe.
  46.  *
  47.  * Revision 4.3.1.2  85/05/13  09:29:28  lwall
  48.  * Added CUSTOMLINES option.
  49.  *
  50.  * Revision 4.3.1.1  85/05/10  11:36:00  lwall
  51.  * Branch for patches.
  52.  *
  53.  * Revision 4.3  85/05/01  11:43:43  lwall
  54.  * Baseline for release with 4.3bsd.
  55.  *
  56.  */
  57.  
  58. #ifdef msdos
  59. #include <dos.h>
  60. #endif
  61.  
  62. #include <conio.h>
  63. #include <stdio.h>
  64. #include <time.h>
  65. #include <stdlib.h>
  66.  
  67. #include "lib.h"
  68. #include "ssleep.h"
  69.  
  70. currentfile();
  71.  
  72. #include "EXTERN.h"
  73. #include "common.h"
  74. #include "rn.h"
  75. #include "term.h"
  76. #include "final.h"
  77. #include "util.h"
  78. #include "artsrch.h"
  79. #include "cheat.h"
  80. #include "help.h"
  81. #include "kfile.h"
  82. #include "rcstuff.h"
  83. #include "head.h"
  84. #include "bits.h"
  85. #include "art.h"
  86. #include "artio.h"
  87. #include "ngstuff.h"
  88. #include "intrp.h"
  89. #include "respond.h"
  90. #include "ngdata.h"
  91. #include "backpage.h"
  92. #include "rcln.h"
  93. #include "last.h"
  94. #include "search.h"
  95.  
  96. #ifdef SERVER
  97. #include "server.h"
  98. #endif
  99.  
  100. #include "INTERN.h"
  101. #include "ng.h"
  102. #include "artstate.h"        /* somebody has to do it */
  103.  
  104. /* art_switch() return values */
  105.  
  106. #define AS_NORM 0
  107. #define AS_INP 1
  108. #define AS_ASK 2
  109. #define AS_CLEAN 3
  110.  
  111. ART_NUM recent_art = 0;      /* previous article #
  112.                               * for '-' command */
  113. ART_NUM curr_art = 0;        /* current article # */
  114. int exit_code = NG_NORM;
  115.  
  116. void
  117.   ng_init()
  118. {
  119.  
  120. #ifdef KILLFILES
  121.    open_kfile(KF_GLOBAL);
  122. #endif
  123.  
  124. #ifdef CUSTOMLINES
  125.    init_compex(&hide_compex);
  126.    init_compex(&page_compex);
  127. #endif
  128. }
  129.  
  130. /* do newsgroup on line ng with name ngname */
  131.  
  132. /* assumes that we are chdir'ed to SPOOL, and assures that that is
  133.  * still true upon return, but chdirs to SPOOL/ngname in between
  134.  *
  135.  * If you can understand this routine, you understand most of the program.
  136.  * The basic structure is:
  137.  * for each desired article
  138.  *    for each desired page
  139.  *       for each line on page
  140.  *          if we need another line from file
  141.  *             get it
  142.  *             if it's a header line
  143.  *                do special things
  144.  *          for each column on page
  145.  *             put out a character
  146.  *          end loop
  147.  *       end loop
  148.  *    end loop
  149.  * end loop
  150.  *
  151.  * (Actually, the pager is in another routine.)
  152.  *
  153.  * The chief problem is deciding what is meant by "desired".  Most of
  154.  * the messiness of this routine is due to the fact that people want
  155.  * to do unstructured things all the time.  I have used a few judicious
  156.  * goto's where I thought it improved readability.  The rest of the messiness
  157.  * arises from trying to be both space and time efficient.  Have fun.
  158.  */
  159.  
  160. int
  161.   do_newsgroup(start_command)
  162.    char *start_command;      /* command to fake up
  163.                               * first */
  164. {
  165.  
  166. #ifdef SERVER
  167.    char ser_line[256];
  168.    char artname[32];
  169.    static long our_pid;
  170.  
  171. #endif                       /* SERVER */
  172.    char oldmode = mode;
  173.    register long i;          /* scratch */
  174.    int skipstate;            /* how many unavailable
  175.                               * articles */
  176.  
  177.    /* have we skipped already? */
  178.  
  179.    char *whatnext = "%sWhat next? [%s]";
  180.  
  181. #ifdef SERVER
  182.    if (our_pid == 0)         /* Agreed, this is gross */
  183.       our_pid = getpid();
  184. #endif                       /* SERVER */
  185.  
  186. #ifdef ARTSEARCH
  187.    srchahead = (scanon && ((ART_NUM) toread[ng]) >= scanon ? -1 : 0);
  188.    /* did they say -S? */
  189. #endif
  190.  
  191.    mode = 'a';
  192.    recent_art = curr_art = 0;
  193.    exit_code = NG_NORM;
  194.  
  195. #ifdef SERVER
  196.    sprintf(ser_line, "GROUP %s", ngname);
  197.    put_server(ser_line);
  198.    if (get_server(ser_line, sizeof (ser_line)) < 0)
  199.    {
  200.       fprintf(stderr, "rrn: Unexpected close of server socket.\n");
  201.       finalize(1);
  202.    }
  203.    if (*ser_line != CHAR_OK)
  204.    {
  205.       if (atoi(ser_line) != ERR_NOGROUP)
  206.          fprintf(stderr, "rrn: server response to GROUP %s:\n%s\n",
  207.                  ngname, ser_line);
  208.       return (-1);
  209.    }
  210. #else                        /* not SERVER */
  211.  
  212. #ifndef msdos
  213.    if (eaccess(ngdir, 5))
  214.    {                         /* directory read
  215.                               * protected? */
  216.       if (eaccess(ngdir, 0))
  217.       {
  218.  
  219. #ifdef VERBOSE
  220.          IF(verbose)
  221.             printf("\nNewsgroup %s does not have a spool directory!\n",
  222.                    ngname) FLUSH;
  223.          ELSE
  224. #endif
  225.  
  226. #ifdef TERSE
  227.             printf("\nNo spool for %s!\n", ngname) FLUSH;
  228. #endif
  229.  
  230. #ifdef CATCHUP
  231.          catch_up(ng);
  232. #endif
  233.  
  234.          toread[ng] = TR_NONE;
  235.       }
  236.       else
  237.       {
  238.  
  239. #ifdef VERBOSE
  240.          IF(verbose)
  241.             printf("\nNewsgroup %s is not currently accessible.\n",
  242.                    ngname) FLUSH;
  243.          ELSE
  244. #endif
  245.  
  246. #ifdef TERSE
  247.             printf("\n%s not readable.\n", ngname) FLUSH;
  248. #endif
  249.  
  250.          toread[ng] = TR_NONE;  /* make this newsgroup
  251.                                  * invisible */
  252.          /* (temporarily) */
  253.       }
  254.       mode = oldmode;
  255.       return -1;
  256.    }
  257. #endif                       /* msdos */
  258.  
  259.    /* chdir to newsgroup subdirectory */
  260.  
  261.    if (chdir(ngdir))
  262.    {
  263.       printerr(ngdir);
  264.       printf(nocd, ngdir) FLUSH;
  265.  
  266.       mode = oldmode;
  267.       return -1;
  268.    }
  269. #endif                       /* SERVER */
  270.  
  271. #ifdef CACHESUBJ
  272.    subj_list = Null(char **);/* no subject list till
  273.                               * needed */
  274. #endif
  275.  
  276.    /* initialize control bitmap */
  277.  
  278.    if (initctl())
  279.    {
  280.       mode = oldmode;
  281.       return -1;
  282.    }
  283.  
  284.    /* FROM HERE ON, RETURN THRU CLEANUP OR WE ARE SCREWED */
  285.  
  286.    in_ng = TRUE;             /* tell the world we are
  287.                               * here */
  288.    forcelast = TRUE;         /* if 0 unread, do not
  289.                               * bomb out */
  290.    art = firstart;
  291.  
  292.    /* remember what newsgroup we were in for sake of posterity */
  293.  
  294.    writelast();
  295.  
  296.    /* see if there are any special searches to do */
  297.  
  298. #ifdef KILLFILES
  299.    open_kfile(KF_LOCAL);
  300.  
  301. #ifdef VERBOSE
  302.    IF(verbose)
  303.       kill_unwanted(firstart, "Looking for articles to kill...\n\n", TRUE);
  304.    ELSE
  305. #endif
  306.  
  307. #ifdef TERSE
  308.       kill_unwanted(firstart, "Killing...\n\n", TRUE);
  309. #endif
  310.  
  311. #endif
  312.  
  313.    /* do they want a special top line? */
  314.  
  315.    firstline = getval("FIRSTLINE", Nullch);
  316.  
  317.    /* custom line suppression, custom page ending */
  318.  
  319. #ifdef CUSTOMLINES
  320.    if (hideline = getval("HIDELINE", Nullch))
  321.       compile(&hide_compex, hideline, TRUE, TRUE);
  322.    if (pagestop = getval("PAGESTOP", Nullch))
  323.       compile(&page_compex, pagestop, TRUE, TRUE);
  324. #endif
  325.  
  326.    /* now read each unread article */
  327.  
  328.    rc_changed = doing_ng = TRUE;        /* enter the twilight
  329.                                          * zone */
  330.    skipstate = 0;            /* we have not skipped
  331.                               * anything (yet) */
  332.    checkcount = 0;           /* do not checkpoint for
  333.                               * a while */
  334.    do_fseek = FALSE;         /* start 1st article at
  335.                               * top */
  336.    if (art > lastart)
  337.       art = firstart;        /* init the for loop
  338.                               * below */
  339.    for (; art <= lastart + 1;)
  340.    {                         /* for each article */
  341.  
  342.       /* do we need to "grow" the newsgroup? */
  343.  
  344.       if (art > lastart || forcegrow)
  345.          grow_ctl();
  346.       check_first(art);      /* make sure firstart is
  347.                               * still 1st */
  348.       if (start_command)
  349.       {                      /* fake up an initial
  350.                               * command? */
  351.          prompt = whatnext;
  352.          strcpy(buf, start_command);
  353.          free(start_command);
  354.          start_command = Nullch;
  355.          art = lastart + 1;
  356.          goto article_level;
  357.       }
  358.       if (art > lastart)
  359.       {                      /* are we off the end
  360.                               * still? */
  361.          ART_NUM ucount = 0; /* count of unread
  362.                               * articles left */
  363.  
  364.          for (i = firstart; i <= lastart; i++)
  365.             if (!(ctl_read(i)))
  366.                ucount++;     /* count the unread
  367.                               * articles */
  368.  
  369. #ifdef DEBUGGING
  370.          /* NOSTRICT */
  371.          if (debug && ((ART_NUM) toread[ng]) != ucount)
  372.             printf("(toread=%ld sb %ld)", (long) toread[ng], (long) ucount)
  373.                FLUSH;
  374. #endif
  375.  
  376.          /* NOSTRICT */
  377.          toread[ng] = (ART_UNREAD) ucount;      /* this is perhaps
  378.                                                  * pointless */
  379.          art = lastart + 1;  /* keep bitmap
  380.                               * references sane */
  381.          if (art != curr_art)
  382.          {
  383.             recent_art = curr_art;
  384.             /* remember last article # (for '-') */
  385.             curr_art = art;  /* remember this article
  386.                               * # */
  387.          }
  388.          if (erase_screen)
  389.             clear();         /* clear the screen */
  390.          else
  391.             fputs("\n\n", stdout) FLUSH;
  392.  
  393. #ifdef VERBOSE
  394.          IF(verbose)
  395.             printf("End of newsgroup %s.", ngname);
  396.          /* print pseudo-article */
  397.          ELSE
  398. #endif
  399.  
  400. #ifdef TERSE
  401.             printf("End of %s", ngname);
  402. #endif
  403.  
  404.          if (ucount)
  405.          {
  406.             printf("  (%ld article%s still unread)",
  407.                    (long) ucount, ucount == 1 ? nullstr : "s");
  408.          }
  409.          else
  410.          {
  411.             if (!forcelast)
  412.                goto cleanup; /* actually exit
  413.                               * newsgroup */
  414.          }
  415.          prompt = whatnext;
  416.  
  417. #ifdef ARTSEARCH
  418.          srchahead = 0;      /* no more subject
  419.                               * search mode */
  420. #endif
  421.  
  422.          fputs("\n\n", stdout) FLUSH;
  423.          skipstate = 0;      /* back to none skipped */
  424.       }
  425.       else if (!reread && was_read(art))
  426.       {
  427.          /* has this article been read? */
  428.          art++;              /* then skip it */
  429.          continue;
  430.       }
  431.       else if
  432.             (!reread && !was_read(art)
  433.  
  434. #ifdef SERVER
  435.                   && nntpopen(art, HEAD) == Nullfp)
  436.       {
  437. #else
  438.                   && artopen(art) == Nullfp)
  439.       {                      /* never read it, &
  440.                               * cannot find it? */
  441.          if (errno != ENOENT)
  442.          {                   /* has it not been
  443.                               * deleted? */
  444.  
  445. #ifdef VERBOSE
  446.             IF(verbose)
  447.                printf("\n(Article %ld exists but is unreadable.)\n",
  448.                       (long) art) FLUSH;
  449.             ELSE
  450. #endif
  451.  
  452. #ifdef TERSE
  453.                printf("\n(%ld unreadable.)\n", (long) art) FLUSH;
  454. #endif
  455.  
  456.             skipstate = 0;
  457.             ssleep(2);
  458.          }
  459. #endif
  460.  
  461.          switch (skipstate++)
  462.          {
  463.           case 0:
  464.             clear();
  465.  
  466. #ifdef VERBOSE
  467.             IF(verbose)
  468.                fputs("Skipping unavailable article", stdout);
  469.             ELSE
  470. #endif
  471.  
  472. #ifdef TERSE
  473.                fputs("Skipping", stdout);
  474. #endif
  475.  
  476.             pad(just_a_sec / 3);
  477.             break;
  478.           case 1:
  479.             fputs("..", stdout);
  480.             fflush(stdout);
  481.             break;
  482.           default:
  483.             putchar('.');
  484.             fflush(stdout);
  485.  
  486. #ifndef SERVER
  487. #define READDIR
  488.  
  489. #ifdef READDIR
  490.             {                /* fast skip patch */
  491.                ART_NUM newart;
  492.  
  493.                if (!(newart = getngmin(".", art)))
  494.                   newart = lastart + 1;
  495.                for (i = art; i < newart; i++)
  496.                   oneless(i);
  497.                art = newart - 1;
  498.             }
  499. #endif
  500.  
  501. #else
  502.             {
  503.                char ser_line[256];
  504.                ART_NUM newart;
  505.  
  506.                put_server("NEXT");
  507.                if (get_server(ser_line, sizeof (ser_line)) < 0)
  508.                {
  509.                   fprintf(stderr,
  510.                           "rrn: unexpected close of server socket.\n");
  511.                   finalize(1);
  512.                }
  513.                if (ser_line[0] != CHAR_OK)
  514.                   newart = lastart + 1;
  515.                else
  516.                   newart = atoi(ser_line + 4);
  517.                for (i = art; i < newart; i++)
  518.                   oneless(i);
  519.                art = newart - 1;
  520.             }
  521. #endif                       /* SERVER */
  522.  
  523.             break;
  524.          }
  525.          oneless(art);       /* mark deleted as read */
  526.          art++;              /* try next article */
  527.          continue;
  528.       }
  529.       else
  530.       {                      /* we have a real live
  531.                               * article */
  532.          skipstate = 0;      /* back to none skipped */
  533.          if (art != curr_art)
  534.          {
  535.             recent_art = curr_art;
  536.             /* remember last article # (for '-') */
  537.             curr_art = art;  /* remember this article
  538.                               * # */
  539.          }
  540.          if (!do_fseek)
  541.          {                   /* starting at top of
  542.                               * article? */
  543.             artline = 0;     /* start at the
  544.                               * beginning */
  545.             topline = -1;    /* and remember top line
  546.                               * of screen */
  547.             /* (line # within article file) */
  548.          }
  549.          clear();            /* clear screen */
  550.          artopen(art);       /* make sure article
  551.                               * file is open */
  552.          if (artfp == Nullfp)
  553.          {                   /* could not find
  554.                               * article? */
  555.             printf("Article %ld of %s is not available.\n\n",
  556.                    (long) art, ngname) FLUSH;
  557.             prompt = whatnext;
  558.  
  559. #ifdef ARTSEARCH
  560.             srchahead = 0;
  561. #endif
  562.          }
  563.          else
  564.          {                   /* found it, so print it */
  565.             switch (do_article())
  566.             {
  567.              case DA_CLEAN: /* quit newsgroup */
  568.                goto cleanup;
  569.              case DA_TOEND: /* do not mark as read */
  570.                goto reask_article;
  571.              case DA_RAISE: /* reparse command at
  572.                               * end of art */
  573.                goto article_level;
  574.              case DA_NORM:  /* normal end of article */
  575.                break;
  576.             }
  577.          }
  578.          mark_as_read(art);  /* mark current article
  579.                               * as read */
  580.          reread = FALSE;
  581.          do_hiding = TRUE;
  582.  
  583. #ifdef ROTATION
  584.          rotate = FALSE;
  585. #endif
  586.       }
  587.  
  588. /* if these gotos bother you, think of this as a little state machine */
  589.  
  590. reask_article:
  591.  
  592. #ifdef MAILCALL
  593.       setmail();
  594. #endif
  595.  
  596.       setdfltcmd();
  597.  
  598. #ifdef CLEAREOL
  599.       if (erase_screen && can_home_clear)
  600.          clear_rest();
  601. #endif                       /* CLEAREOL */
  602.  
  603.       unflush_output();      /* disable any ^O in
  604.                               * effect */
  605.       standout();            /* enter standout mode */
  606.       printf(prompt, mailcall, dfltcmd);        /* print prompt,
  607.                                                  * whatever it is */
  608.       un_standout();         /* leave standout mode */
  609.       putchar(' ');
  610.       fflush(stdout);
  611. reinp_article:
  612.       eat_typeahead();
  613.  
  614. #ifdef PENDING
  615.       look_ahead();          /* see what we can do in
  616.                               * advance */
  617.       if (!input_pending())
  618.          collect_subjects(); /* loads subject cache
  619.                               * until */
  620.       /* input is pending */
  621. #endif
  622.  
  623.       getcmd(buf);
  624.       if (errno || *buf == '\f')
  625.       {
  626.          if (LINES < 100 && !int_count)
  627.             *buf = '\f';     /* on CONT fake up
  628.                               * refresh */
  629.          else
  630.          {
  631.             putchar('\n') FLUSH;        /* but only on a crt */
  632.             goto reask_article;
  633.          }
  634.       }
  635. article_level:
  636.  
  637.       /* parse and process article level command */
  638.  
  639.       switch (art_switch())
  640.       {
  641.        case AS_INP:          /* multichar command
  642.                               * rubbed out */
  643.          goto reinp_article;
  644.        case AS_ASK:          /* reprompt "End of
  645.                               * article..." */
  646.          goto reask_article;
  647.        case AS_CLEAN:        /* exit newsgroup */
  648.          goto cleanup;
  649.        case AS_NORM:         /* display article art */
  650.          break;
  651.       }
  652.    }                         /* end of article
  653.                               * selection loop */
  654.  
  655. /* shut down newsgroup */
  656.  
  657. cleanup:
  658.  
  659. #ifdef KILLFILES
  660.    kill_unwanted(firstart, "\nCleaning up...\n\n", FALSE);
  661.    /* do cleanup from KILL file, if any */
  662. #endif
  663.  
  664.    in_ng = FALSE;            /* leave newsgroup state */
  665.    if (artfp != Nullfp)
  666.    {                         /* article still open? */
  667.       fclose(artfp);         /* close it */
  668.       artfp = Nullfp;        /* and tell the world */
  669.  
  670. #ifdef SERVER
  671.       sprintf(artname, "/tmp/rrn%ld.%ld", (long) openart, our_pid);
  672.       UNLINK(artname);
  673. #endif                       /* SERVER */
  674.  
  675.       openart = 0;
  676.    }
  677.    putchar('\n') FLUSH;
  678.    yankback();               /* do a Y command */
  679.    restore_ng();             /* reconstitute .newsrc
  680.                               * line */
  681.    doing_ng = FALSE;         /* tell sig_catcher to
  682.                               * cool it */
  683.    free(ctlarea);            /* return the control
  684.                               * area */
  685.  
  686. #ifdef CACHESUBJ
  687.    if (subj_list)
  688.    {
  689.       for (i = OFFSET(lastart); i >= 0; --i)
  690.          if (subj_list[i])
  691.             free(subj_list[i]);
  692.  
  693. #ifndef lint
  694.       free((char *) subj_list);
  695. #endif                       /* lint */
  696.    }
  697. #endif
  698.  
  699.    write_rc();               /* and update .newsrc */
  700.    rc_changed = FALSE;       /* tell sig_catcher it
  701.                               * is ok */
  702.    if (chdir(spool))
  703.    {
  704.       printerr(ngdir);
  705.       printf(nocd, spool) FLUSH;
  706.       sig_catcher(0);
  707.    }
  708.  
  709. #ifdef KILLFILES
  710.    if (localkfp)
  711.    {
  712.       fclose(localkfp);
  713.       localkfp = Nullfp;
  714.    }
  715. #endif
  716.  
  717.    mode = oldmode;
  718.    return exit_code;
  719. }                            /* Whew! */
  720.  
  721. /* decide what to do at the end of an article */
  722.  
  723. int
  724.   art_switch()
  725. {
  726.    register ART_NUM i;
  727.  
  728.    setdef(buf, dfltcmd);
  729.  
  730. #ifdef VERIFY
  731.    printcmd();
  732. #endif
  733.  
  734.    switch (*buf)
  735.    {
  736.     case 'p':                /* find previous unread
  737.                               * article */
  738.       do
  739.       {
  740.          if (art <= firstart)
  741.             break;
  742.          art--;
  743.  
  744. #ifdef SERVER
  745.       } while (was_read(art) || nntpopen(art, HEAD) == Nullfp);
  746. #else
  747.       } while (was_read(art) || artopen(art) == Nullfp);
  748. #endif
  749.  
  750. #ifdef ARTSEARCH
  751.       srchahead = 0;
  752. #endif
  753.  
  754.       return AS_NORM;
  755.     case 'P':                /* goto previous article */
  756.       if (art > absfirst)
  757.          art--;
  758.       else
  759.       {
  760.  
  761. #ifdef VERBOSE
  762.          IF(verbose)
  763.             fputs("\n\
  764. There are no articles prior to this one.\n\
  765. ", stdout) FLUSH;
  766.          ELSE
  767. #endif
  768.  
  769. #ifdef TERSE
  770.             fputs("\nNo previous articles\n", stdout) FLUSH;
  771. #endif
  772.  
  773.          return AS_ASK;
  774.       }
  775.       reread = TRUE;
  776.  
  777. #ifdef ARTSEARCH
  778.       srchahead = 0;
  779. #endif
  780.  
  781.       return AS_NORM;
  782.     case '-':
  783.       if (recent_art)
  784.       {
  785.          art = recent_art;
  786.          reread = TRUE;
  787.  
  788. #ifdef ARTSEARCH
  789.          srchahead = -(srchahead != 0);
  790. #endif
  791.  
  792.          return AS_NORM;
  793.       }
  794.       else
  795.       {
  796.          exit_code = NG_MINUS;
  797.          return AS_CLEAN;
  798.       }
  799.     case 'n':                /* find next unread
  800.                               * article? */
  801.       if (art > lastart)
  802.       {
  803.          if (toread[ng])
  804.             art = firstart;
  805.          else
  806.             return AS_CLEAN;
  807.       }
  808.  
  809. #ifdef ARTSEARCH
  810.       else if (scanon && srchahead)
  811.       {
  812.          *buf = Ctl('n');
  813.          goto normal_search;
  814.       }
  815. #endif
  816.  
  817.       else
  818.          art++;
  819.  
  820. #ifdef ARTSEARCH
  821.       srchahead = 0;
  822. #endif
  823.  
  824.       return AS_NORM;
  825.     case 'N':                /* goto next article */
  826.       if (art > lastart)
  827.          art = absfirst;
  828.       else
  829.          art++;
  830.       if (art <= lastart)
  831.          reread = TRUE;
  832.  
  833. #ifdef ARTSEARCH
  834.       srchahead = 0;
  835. #endif
  836.  
  837.       return AS_NORM;
  838.     case '$':
  839.       art = lastart + 1;
  840.       forcelast = TRUE;
  841.  
  842. #ifdef ARTSEARCH
  843.       srchahead = 0;
  844. #endif
  845.  
  846.       return AS_NORM;
  847.     case '1':
  848.     case '2':
  849.     case '3':                /* goto specified
  850.                               * article */
  851.     case '4':
  852.     case '5':
  853.     case '6':                /* or do something with
  854.                               * a range */
  855.     case '7':
  856.     case '8':
  857.     case '9':
  858.     case '.':
  859.       forcelast = TRUE;
  860.       switch (numnum())
  861.       {
  862.        case NN_INP:
  863.          return AS_INP;
  864.        case NN_ASK:
  865.          return AS_ASK;
  866.        case NN_REREAD:
  867.          reread = TRUE;
  868.  
  869. #ifdef ARTSEARCH
  870.          if (srchahead)
  871.             srchahead = -1;
  872. #endif
  873.  
  874.          break;
  875.        case NN_NORM:
  876.          if (was_read(art))
  877.          {
  878.             art = firstart;
  879.             pad(just_a_sec / 3);
  880.          }
  881.          else
  882.             return AS_ASK;
  883.          break;
  884.       }
  885.       return AS_NORM;
  886.     case Ctl('k'):
  887.       edit_kfile();
  888.       return AS_ASK;
  889.     case 'K':
  890.     case 'k':
  891.     case Ctl('n'):
  892.     case Ctl('p'):
  893.     case '/':
  894.     case '?':
  895.  
  896. #ifdef ARTSEARCH
  897. normal_search:
  898.       {                      /* search for article by
  899.                               * pattern */
  900.          char cmd = *buf;
  901.  
  902.          reread = TRUE;      /* assume this */
  903.          switch (art_search(buf, (sizeof buf), TRUE))
  904.          {
  905.           case SRCH_ERROR:
  906.             return AS_ASK;
  907.           case SRCH_ABORT:
  908.             return AS_INP;
  909.           case SRCH_INTR:
  910.  
  911. #ifdef VERBOSE
  912.             IF(verbose)
  913.                printf("\n(Interrupted at article %ld)\n", (long) art) FLUSH;
  914.             ELSE
  915. #endif
  916.  
  917. #ifdef TERSE
  918.                printf("\n(Intr at %ld)\n", (long) art) FLUSH;
  919. #endif
  920.  
  921.             art = curr_art;
  922.             /* restore to current article */
  923.             return AS_ASK;
  924.           case SRCH_DONE:
  925.             fputs("done\n", stdout) FLUSH;
  926.             pad(just_a_sec / 3);        /* 1/3 second */
  927.             if (srchahead)
  928.                art = firstart;
  929.             else
  930.                art = curr_art;
  931.             reread = FALSE;
  932.             return AS_NORM;
  933.           case SRCH_SUBJDONE:
  934.  
  935. #ifdef UNDEF
  936.             fputs("\n\n\n\nSubject not found.\n", stdout) FLUSH;
  937.             pad(just_a_sec / 3);        /* 1/3 second */
  938. #endif
  939.  
  940.             art = firstart;
  941.             reread = FALSE;
  942.             return AS_NORM;
  943.           case SRCH_NOTFOUND:
  944.             fputs("\n\n\n\nNot found.\n", stdout) FLUSH;
  945.             art = curr_art;  /* restore to current
  946.                               * article */
  947.             return AS_ASK;
  948.           case SRCH_FOUND:
  949.             if (cmd == Ctl('n') || cmd == Ctl('p'))
  950.                oldsubject = TRUE;
  951.             break;
  952.          }
  953.          return AS_NORM;
  954.       }
  955. #else
  956.       buf[1] = '\0';
  957.       notincl(buf);
  958.       return AS_ASK;
  959. #endif
  960.  
  961.     case 'u':                /* unsubscribe from this
  962.                               * newsgroup? */
  963.       rcchar[ng] = NEGCHAR;
  964.       return AS_CLEAN;
  965.     case 'M':
  966.  
  967. #ifdef DELAYMARK
  968.       if (art <= lastart)
  969.       {
  970.          delay_unmark(art);
  971.          printf("\nArticle %ld will return.\n", (long) art) FLUSH;
  972.       }
  973. #else
  974.       notincl("M");
  975. #endif
  976.  
  977.       return AS_ASK;
  978.     case 'm':
  979.       if (art <= lastart)
  980.       {
  981.          unmark_as_read(art);
  982.          printf("\nArticle %ld marked as still unread.\n", (long) art) FLUSH;
  983.       }
  984.       return AS_ASK;
  985.     case 'c':                /* catch up */
  986. reask_catchup:
  987.  
  988. #ifdef VERBOSE
  989.       IF(verbose)
  990.          in_char("\nDo you really want to mark everything as read? [yn] ",
  991.                  'C');
  992.       ELSE
  993. #endif
  994.  
  995. #ifdef TERSE
  996.          in_char("\nReally? [ynh] ", 'C');
  997. #endif
  998.  
  999.       putchar('\n') FLUSH;
  1000.       setdef(buf, "y");
  1001.  
  1002. #ifdef VERIFY
  1003.       printcmd();
  1004. #endif
  1005.  
  1006.       if (*buf == 'h')
  1007.       {
  1008.  
  1009. #ifdef VERBOSE
  1010.          IF(verbose)
  1011.             fputs("\
  1012. Type y or SP to mark all articles as read.\n\
  1013. Type n to leave articles marked as they are.\n\
  1014. Type u to mark everything read and unsubscribe.\n\
  1015. ", stdout) FLUSH;
  1016.          ELSE
  1017. #endif
  1018.  
  1019. #ifdef TERSE
  1020.             fputs("\
  1021. y or SP to mark all read.\n\
  1022. n to forget it.\n\
  1023. u to mark all and unsubscribe.\n\
  1024. ", stdout) FLUSH;
  1025. #endif
  1026.  
  1027.          goto reask_catchup;
  1028.       }
  1029.       else if (*buf == 'n' || *buf == 'q')
  1030.       {
  1031.          return AS_ASK;
  1032.       }
  1033.       else if (*buf != 'y' && *buf != 'u')
  1034.       {
  1035.          fputs(hforhelp, stdout) FLUSH;
  1036.          settle_down();
  1037.          goto reask_catchup;
  1038.       }
  1039.       for (i = firstart; i <= lastart; i++)
  1040.       {
  1041.          oneless(i);         /* mark as read */
  1042.       }
  1043.  
  1044. #ifdef DELAYMARK
  1045.       if (dmfp)
  1046.          yankback();
  1047. #endif
  1048.  
  1049.       if (*buf == 'u')
  1050.       {
  1051.          rcchar[ng] = NEGCHAR;
  1052.          return AS_CLEAN;
  1053.       }
  1054.       art = lastart + 1;
  1055.       forcelast = FALSE;
  1056.       return AS_NORM;
  1057.     case 'Q':
  1058.       exit_code = NG_ASK;
  1059.       /* FALL THROUGH */
  1060.     case 'q':                /* go back up to
  1061.                               * newsgroup level? */
  1062.       return AS_CLEAN;
  1063.     case 'j':
  1064.       putchar('\n') FLUSH;
  1065.       if (art <= lastart)
  1066.          mark_as_read(art);
  1067.       return AS_ASK;
  1068.     case 'h':
  1069.       {                      /* help? */
  1070.          int cmd;
  1071.  
  1072.          if ((cmd = help_art()) > 0)
  1073.             pushchar(cmd);
  1074.          return AS_ASK;
  1075.       }
  1076.     case '&':
  1077.       if (switcheroo())      /* get rest of command */
  1078.          return AS_INP;      /* if rubbed out, try
  1079.                               * something else */
  1080.       return AS_ASK;
  1081.     case '#':
  1082.  
  1083. #ifdef VERBOSE
  1084.       IF(verbose)
  1085.          printf("\nThe last article is %ld.\n", (long) lastart) FLUSH;
  1086.       ELSE
  1087. #endif
  1088.  
  1089. #ifdef TERSE
  1090.          printf("\n%ld\n", (long) lastart) FLUSH;
  1091. #endif
  1092.  
  1093.       return AS_ASK;
  1094.     case '=':
  1095.       {
  1096.          char tmpbuf[256];
  1097.          ART_NUM oldart = art;
  1098.          int cmd;
  1099.          char *subjline = getval("SUBJLINE", Nullch);
  1100.  
  1101. #ifndef CACHESUBJ
  1102.          char *s;
  1103.  
  1104. #endif
  1105.  
  1106.          page_init();
  1107.  
  1108. #ifdef CACHESUBJ
  1109.          if (!subj_list)
  1110.             fetchsubj(art, TRUE, FALSE);
  1111. #endif
  1112.  
  1113.          for (i = firstart; i <= lastart && !int_count; i++)
  1114.          {
  1115.  
  1116. #ifdef CACHESUBJ
  1117.             if (!was_read(i) &&
  1118.                   (subj_list[OFFSET(i)] != Nullch || fetchsubj(i, FALSE, FALSE)) &&
  1119.                   *subj_list[OFFSET(i)])
  1120.             {
  1121.                sprintf(tmpbuf, "%5ld ", i);
  1122.                if (subjline)
  1123.                {
  1124.                   art = i;
  1125.                   interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline);
  1126.                }
  1127.                else
  1128.                   safecpy(tmpbuf + 6, subj_list[OFFSET(i)],
  1129.                           (sizeof tmpbuf) - 6);
  1130.                if (cmd = print_lines(tmpbuf, NOMARKING))
  1131.                {
  1132.                   if (cmd > 0)
  1133.                      pushchar(cmd);
  1134.                   break;
  1135.                }
  1136.             }
  1137. #else
  1138.             if (!was_read(i) && (s = fetchsubj(i, FALSE, FALSE)) && *s)
  1139.             {
  1140.                sprintf(tmpbuf, "%5ld ", i);
  1141.                if (subjline)
  1142.                {             /* probably fetches it
  1143.                               * again! */
  1144.                   art = i;
  1145.                   interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline);
  1146.                }
  1147.                else
  1148.                   safecpy(tmpbuf + 6, s, (sizeof tmpbuf) - 6);
  1149.                if (cmd = print_lines(tmpbuf, NOMARKING))
  1150.                {
  1151.                   if (cmd > 0)
  1152.                      pushchar(cmd);
  1153.                   break;
  1154.                }
  1155.             }
  1156. #endif
  1157.          }
  1158.          int_count = 0;
  1159.          art = oldart;
  1160.          return AS_ASK;
  1161.       }
  1162.     case '^':
  1163.       art = firstart;
  1164.  
  1165. #ifdef ARTSEARCH
  1166.       srchahead = 0;
  1167. #endif
  1168.  
  1169.       return AS_NORM;
  1170.  
  1171. #if defined(CACHESUBJ) && defined(DEBUGGING)
  1172.     case 'D':
  1173.       printf("\nFirst article: %ld\n", (long) firstart) FLUSH;
  1174.       if (!subj_list)
  1175.          fetchsubj(art, TRUE, FALSE);
  1176.       if (subj_list != Null(char **))
  1177.       {
  1178.          for (i = 1; i <= lastart && !int_count; i++)
  1179.          {
  1180.             if (subj_list[OFFSET(i)])
  1181.                printf("%5ld %c %s\n",
  1182.                       i, (was_read(i) ? 'y' : 'n'), subj_list[OFFSET(i)]) FLUSH;
  1183.          }
  1184.       }
  1185.       int_count = 0;
  1186.       return AS_ASK;
  1187. #endif
  1188.  
  1189.     case 'v':
  1190.       if (art <= lastart)
  1191.       {
  1192.          reread = TRUE;
  1193.          do_hiding = FALSE;
  1194.       }
  1195.       return AS_NORM;
  1196.  
  1197. #ifdef ROTATION
  1198.     case Ctl('x'):
  1199. #endif
  1200.  
  1201.     case Ctl('r'):
  1202.  
  1203. #ifdef ROTATION
  1204.       rotate = (*buf == Ctl('x'));
  1205. #endif
  1206.  
  1207.       if (art <= lastart)
  1208.          reread = TRUE;
  1209.       return AS_NORM;
  1210.  
  1211. #ifdef ROTATION
  1212.     case 'X':
  1213.       rotate = !rotate;
  1214.       /* FALL THROUGH */
  1215. #else
  1216.     case Ctl('x'):
  1217.     case 'x':
  1218.     case 'X':
  1219.       notincl("x");
  1220.       return AS_ASK;
  1221. #endif
  1222.  
  1223.     case 'l':
  1224.     case Ctl('l'):           /* refresh screen */
  1225.       if (art <= lastart)
  1226.       {
  1227.          reread = TRUE;
  1228.          clear();
  1229.          do_fseek = TRUE;
  1230.          artline = topline;
  1231.          if (artline < 0)
  1232.             artline = 0;
  1233.       }
  1234.       return AS_NORM;
  1235.     case 'b':
  1236.     case Ctl('b'):           /* back up a page */
  1237.       if (art <= lastart)
  1238.       {
  1239.          ART_LINE target;
  1240.  
  1241.          reread = TRUE;
  1242.          clear();
  1243.          do_fseek = TRUE;
  1244.          target = topline - (LINES - 2);
  1245.          artline = topline;
  1246.          if (artline > 0)
  1247.             do
  1248.             {
  1249.                artline--;
  1250.             } while (artline >= 0 && artline > target &&
  1251.                      vrdary(artline - 1) >= 0);
  1252.          topline = artline;
  1253.          if (artline < 0)
  1254.             artline = 0;
  1255.       }
  1256.       return AS_NORM;
  1257.     case '!':                /* shell escape */
  1258.       if (escapade())
  1259.          return AS_INP;
  1260.       return AS_ASK;
  1261.     case 'C':
  1262.       {
  1263.          cancel_article();
  1264.          return AS_ASK;
  1265.       }
  1266.     case 'R':
  1267.     case 'r':
  1268.       {                      /* reply? */
  1269.          reply();
  1270.          return AS_ASK;
  1271.       }
  1272.     case 'F':
  1273.     case 'f':
  1274.       {                      /* followup command */
  1275.          followup();
  1276.          forcegrow = TRUE;   /* recalculate lastart */
  1277.          return AS_ASK;
  1278.       }
  1279.     case '|':
  1280.     case 'w':
  1281.     case 'W':
  1282.     case 's':
  1283.     case 'S':                /* save command */
  1284.       if (save_article() == SAVE_ABORT)
  1285.          return AS_INP;
  1286.       return AS_ASK;
  1287.  
  1288. #ifdef DELAYMARK
  1289.     case 'Y':                /* yank back M articles */
  1290.       yankback();
  1291.       art = firstart;        /* from the beginning */
  1292.       return AS_NORM;        /* pretend nothing
  1293.                               * happened */
  1294. #endif
  1295.  
  1296. #ifdef STRICTCR
  1297.     case '\n':
  1298.       fputs(badcr, stdout) FLUSH;
  1299.       return AS_ASK;
  1300. #endif
  1301.  
  1302.     default:
  1303.       printf("\n%s", hforhelp) FLUSH;
  1304.       settle_down();
  1305.       return AS_ASK;
  1306.    }
  1307. }
  1308.  
  1309. #ifdef MAILCALL
  1310. /* see if there is any mail */
  1311.  
  1312. void
  1313.   setmail()
  1314. {
  1315.    if (!(mailcount++))
  1316.    {
  1317.       char *mailfile = filexp(getval("MAILFILE", MAILFILE));
  1318.  
  1319.       if (stat(mailfile, &filestat) < 0 || !filestat.st_size
  1320.             || filestat.st_atime > filestat.st_mtime)
  1321.          mailcall = nullstr;
  1322.       else
  1323.          mailcall = getval("MAILCALL", "(Mail) ");
  1324.    }
  1325.    mailcount %= 10;          /* check every 10
  1326.                               * articles */
  1327. }
  1328.  
  1329. #endif
  1330.  
  1331. void
  1332.   setdfltcmd()
  1333. {
  1334.    if (toread[ng])
  1335.    {
  1336.  
  1337. #ifdef ARTSEARCH
  1338.       if (srchahead)
  1339.          dfltcmd = "^Nnpq";
  1340.       else
  1341. #endif
  1342.  
  1343.          dfltcmd = "npq";
  1344.    }
  1345.    else
  1346.    {
  1347.       if (art > lastart)
  1348.          dfltcmd = "qnp";
  1349.       else
  1350.          dfltcmd = "npq";
  1351.    }
  1352. }
  1353.